package ntlmssp

import (
	
	
	
	
	
	
	
)

type authenicateMessage struct {
	LmChallengeResponse []byte
	NtChallengeResponse []byte

	TargetName string
	UserName   string

	// only set if negotiateFlag_NTLMSSP_NEGOTIATE_KEY_EXCH
	EncryptedRandomSessionKey []byte

	NegotiateFlags negotiateFlags

	MIC []byte
}

type authenticateMessageFields struct {
	messageHeader
	LmChallengeResponse varField
	NtChallengeResponse varField
	TargetName          varField
	UserName            varField
	Workstation         varField
	_                   [8]byte
	NegotiateFlags      negotiateFlags
}

func ( authenicateMessage) () ([]byte, error) {
	if !.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEUNICODE) {
		return nil, errors.New("Only unicode is supported")
	}

	,  := toUnicode(.TargetName), toUnicode(.UserName)
	 := toUnicode("")

	 := binary.Size(&authenticateMessageFields{})
	 := authenticateMessageFields{
		messageHeader:       newMessageHeader(3),
		NegotiateFlags:      .NegotiateFlags,
		LmChallengeResponse: newVarField(&, len(.LmChallengeResponse)),
		NtChallengeResponse: newVarField(&, len(.NtChallengeResponse)),
		TargetName:          newVarField(&, len()),
		UserName:            newVarField(&, len()),
		Workstation:         newVarField(&, len()),
	}

	.NegotiateFlags.Unset(negotiateFlagNTLMSSPNEGOTIATEVERSION)

	 := bytes.Buffer{}
	if  := binary.Write(&, binary.LittleEndian, &);  != nil {
		return nil, 
	}
	if  := binary.Write(&, binary.LittleEndian, &.LmChallengeResponse);  != nil {
		return nil, 
	}
	if  := binary.Write(&, binary.LittleEndian, &.NtChallengeResponse);  != nil {
		return nil, 
	}
	if  := binary.Write(&, binary.LittleEndian, &);  != nil {
		return nil, 
	}
	if  := binary.Write(&, binary.LittleEndian, &);  != nil {
		return nil, 
	}
	if  := binary.Write(&, binary.LittleEndian, &);  != nil {
		return nil, 
	}

	return .Bytes(), nil
}

//ProcessChallenge crafts an AUTHENTICATE message in response to the CHALLENGE message
//that was received from the server
func ( []byte, ,  string,  bool) ([]byte, error) {
	if  == "" &&  == "" {
		return nil, errors.New("Anonymous authentication not supported")
	}

	var  challengeMessage
	if  := .UnmarshalBinary();  != nil {
		return nil, 
	}

	if .NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATELMKEY) {
		return nil, errors.New("Only NTLM v2 is supported, but server requested v1 (NTLMSSP_NEGOTIATE_LM_KEY)")
	}
	if .NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEKEYEXCH) {
		return nil, errors.New("Key exchange requested but not supported (NTLMSSP_NEGOTIATE_KEY_EXCH)")
	}
	
	if ! {
		.TargetName = ""
	}

	 := authenicateMessage{
		UserName:       ,
		TargetName:     .TargetName,
		NegotiateFlags: .NegotiateFlags,
	}

	 := .TargetInfo[avIDMsvAvTimestamp]
	if  == nil { // no time sent, take current time
		 := uint64(time.Now().UnixNano()) / 100
		 += 116444736000000000 // add time between unix & windows offset
		 = make([]byte, 8)
		binary.LittleEndian.PutUint64(, )
	}

	 := make([]byte, 8)
	rand.Reader.Read()

	 := getNtlmV2Hash(, , .TargetName)

	.NtChallengeResponse = computeNtlmV2Response(,
		.ServerChallenge[:], , , .TargetInfoRaw)

	if .TargetInfoRaw == nil {
		.LmChallengeResponse = computeLmV2Response(,
			.ServerChallenge[:], )
	}
	return .MarshalBinary()
}

func ( []byte, ,  string) ([]byte, error) {
	if  == "" &&  == "" {
		return nil, errors.New("Anonymous authentication not supported")
	}

	var  challengeMessage
	if  := .UnmarshalBinary();  != nil {
		return nil, 
	}

	if .NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATELMKEY) {
		return nil, errors.New("Only NTLM v2 is supported, but server requested v1 (NTLMSSP_NEGOTIATE_LM_KEY)")
	}
	if .NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEKEYEXCH) {
		return nil, errors.New("Key exchange requested but not supported (NTLMSSP_NEGOTIATE_KEY_EXCH)")
	}

	 := authenicateMessage{
		UserName:       ,
		TargetName:     .TargetName,
		NegotiateFlags: .NegotiateFlags,
	}

	 := .TargetInfo[avIDMsvAvTimestamp]
	if  == nil { // no time sent, take current time
		 := uint64(time.Now().UnixNano()) / 100
		 += 116444736000000000 // add time between unix & windows offset
		 = make([]byte, 8)
		binary.LittleEndian.PutUint64(, )
	}

	 := make([]byte, 8)
	rand.Reader.Read()

	 := strings.Split(, ":")
	if len() > 1 {
		 = [1]
	}
	,  := hex.DecodeString()
	if  != nil {
		return nil, 
	}
	 := hmacMd5(, toUnicode(strings.ToUpper()+.TargetName))

	.NtChallengeResponse = computeNtlmV2Response(,
		.ServerChallenge[:], , , .TargetInfoRaw)

	if .TargetInfoRaw == nil {
		.LmChallengeResponse = computeLmV2Response(,
			.ServerChallenge[:], )
	}
	return .MarshalBinary()
}